#include <stdio.h>
#include "type.h"
#include "btree.h"

/* data structure */
struct root_node content, file_index;

/* Store the token of the file */
struct fifo_head token;
/* Two callback fucntions for FIFO token */
static void *file_input_token_alloc(void *arg)
{
	return arg;
}

static void file_input_token_free(void *arg)
{
	return;
}

struct file_db
{
	i_int8_t *name;
	/* structure insided another structure
	 * only used by structer
	 */
	struct structure_db *sub_db;
	/* For function, it's local variable */
	struct list *member;
};

void file_input_init(void)
{
	btree_init (structure);
	btree_init (function);
	btree_init (macro);
	btree_init (global);
}

static i_int8_t *file_input_skip_space(i_int8_t *buf)
{
	i_int8_t *ptr = buf;

	while ((*ptr == ' ' || *ptr == '\t') && ptr++);

	return ptr;
}

/* Return true: ignore the line */
static bool file_input_ignore_line(i_int8_t *buf)
{
	i_int8_t *ptr;

	ptr = file_input_skip_space(buf);

	/* ignore empty line, and macro, excluding #define */
	if (*ptr == 0
		|| *ptr == '\n'
		|| (*ptr == '#'
		&& strncmp (ptr, "#define", 7)))
		return true;

	return false;
}

static void file_input_remove_comments_none(i_int8_t *buf)
{
	i_int8_t *d_slash, *slash_star, *star_slash,
			 *str_begin, *str_end;
	i_int8_t *ptr;

	d_slash = strstr(buf, "//");
	slash_star = strstr(buf, "/*");
	star_slash = strstr(buf, "*/");

	/*------------------begin-----------------------------*/
	/*Ignore the comments characters between double-quotes*/
	str_end = str_begin = strstr(buf, "\"");
	/* Find the real tailing quote */
	while (str_end
		&& (str_end = strstr(str_end+1, "\"")) != NULL
		&& *(str_end-1) == '\\');

	if (str_begin && d_slash > str_begin
		&& (!str_end || d_slash < str_end))
	{
		d_slash = NULL;
	}
	if (str_begin && slash_star > str_begin
		&& (!str_end || slash_star < str_end))
	{
		slash_star = NULL;
	}

	if (str_begin && star_slash > str_begin
		&& (!str_end || star_slash < str_end))
	{
		star_slash = NULL;
	}
	/*------------------end-----------------------------*/

	ptr = file_input_skip_space(buf);

	/* Begin #if 0 */
	if (!strncmp(ptr, "#if", 3))
	{
		ptr = file_input_skip_space(ptr + 3);
		if (*ptr == '0')
		{
			*buf = 0;
			parse_comments = COMMENTS_IF0;
			return;
		}
	}

	if (d_slash && (!slash_star || slash_star > d_slash))
	{
		*d_slash = 0;
		return;
	}

	if (slash_star)
	{
		if (star_slash)
		{
			strcpy (slash_star, star_slash+2);
		}
		else
		{
			*slash_star = 0;
			parse_comments = COMMENTS_STAR;
		}
		return;
	}

	if (str_begin && !str_end)
	{
		parse_comments = COMMENTS_STR;
		return;
	}
}

static void file_input_remove_comments_star(i_int8_t *buf)
{
	i_int8_t *d_slash, *star_slash;
	i_int8_t *ptr;

	d_slash = strstr(buf, "//");
	star_slash = strstr(buf, "*/");

	ptr = file_input_skip_space(buf);

	if (!star_slash)
	{
		buf[0] = 0;
		return;
	}
	if (d_slash && star_slash && star_slash < d_slash)
	{
		*d_slash = 0;
	}
	if (star_slash)
	{
		strcpy (buf, star_slash+2);
		parse_comments = COMMENTS_NONE;
		return;
	}
}

static void file_input_remove_comments_if0(i_int8_t *buf)
{
	i_int8_t *ptr;

	ptr = file_input_skip_space(buf);
	/* #endif corresponding to #if 0 */
	if (!strncmp(ptr, "#endif", 6))
	{
		parse_comments = COMMENTS_NONE;
	}

	*buf = 0;
}

static void file_input_remove_comments_str(i_int8_t *buf)
{
	i_int8_t *ptr = buf;

	if (*ptr != '\"')
	{
	    /* Find the real tailing quote */
		while (ptr
			&& (ptr = strstr(ptr+1, "\"")) != NULL
			&& *(ptr-1) == '\\');
	}

	if (ptr)
	{
		parse_comments = COMMENTS_NONE;
		file_input_remove_comments_none(ptr+1);
	}
}

/* The type must correspond to the functions
 * defined by file_input_remove_comments
 */
enum comments_type
{
	COMMENTS_NONE,
	COMMENTS_STAR,
	COMMENTS_IF0,
	/* To deal with comments characters
	 * surrounded by double-quotes
	 */
	COMMENTS_STR,
};

static void (*file_input_remove_comments[])(i_int8_t *) =
{
	file_input_remove_comments_none,
	file_input_remove_comments_star,
	file_input_remove_comments_if0,
	file_input_remove_comments_str,
};

/* store the state of current parsing */
static u_int32_t parse_comments = COMMENTS_NONE;

static void file_input_build_db_none(i_int8_t *buf, i_int32_t line)
{
}

static void file_input_build_db_struct_like(i_int8_t *buf, i_int32_t line)
{
}

static void file_input_build_db_struct(i_int8_t *buf, i_int32_t line)
{
}

static void file_input_build_db_func_like(i_int8_t *buf, i_int32_t line)
{
}

static void file_input_build_db_func(i_int8_t *buf, i_int32_t line)
{
}

enum tag_type
{
	TAG_NONE,
	TAG_STRUCT_LIKE,
	TAG_STRUCT,
	TAG_FUNC_LIKE,
	TAG_FUNC,
};

static void (*file_input_build_db[])(i_int8_t *, i_int32_t) =
{
	file_input_build_db_none,
	file_input_build_db_struct_like,
	file_input_build_db_struct,
	file_input_build_db_func_like,
	file_input_build_db_func,
};

/* store the state of current parsing */
static u_int32_t parse_tag = TAG_NONE;

static bool file_input_is_valid_name(i_int8_t character)
{
	if (character == '_'
		|| (character >= 'a' && character <= 'z')
		|| (character >= 'A' && character <= 'Z')
		|| (character >= '0' && character <= '9'))
		return true;

	return false;
}
static i_int8_t *file_input_split (i_int8_t *buf)
{
	i_int8_t *begin, *end;

	begin = file_input_skip_space(buf);
	for (end = begin; file_input_is_valid_name (*end); end++);
	memcpy ()
}


static void file_input_build_db(i_int8_t *buf, u_int32_t lineno)
{
}

void file_input_read_file(i_int8_t *name)
{
	FILE *fp;
	i_int8_t buf[512];
	u_int32_t lineno = 0;

	if (name == NULL)
	{
		fprintf (stderr, "Read NULL file!\n");
		return;
	}
	if ((fp = fopen (name, "r")) == NULL)
	{
		fprintf (stderr, "Open file %s error!\n\r", name);
		return;
	}

	fifo_init (&token, file_input_token_alloc, file_input_token_free);

	while (fgets (buf, 512, fp))
	{
		lineno++;

		file_input_remove_comments[parse_comments](buf);
		
		if (file_input_ignore_line (buf))
			continue;

		file_input_build_db (buf, lineno);
	}

	fclose (fp);
}

